/** file InstrumentMonophonique.cpp
    author belot.nicolas
*/

#include "InstrumentMonophonique.h"
#include "SampleFactory.h"
#include "ChangePitch.h"
#include <iostream>
#include <cmath>
namespace libtrckr {

InstrumentMonophonique::InstrumentMonophonique():Instrument(),_samples(0,NULL),attack(0,string()){
	_name=string();
	_tune=string();
	_partition=queue<INote>();
	current=0;
	duration = elapsed = 0;
	effects=NULL;
//	_samples=map<string, INote>();
}

InstrumentMonophonique::InstrumentMonophonique(string Name):Instrument(),_name(Name){
	_tune=string();
	_partition=queue<INote>();
	current=0;
	duration = elapsed = 0;
//	_samples=map<string, INote>();
}

InstrumentMonophonique::InstrumentMonophonique(const InstrumentMonophonique & im):Instrument(im),
	_name(im._name), 
	_tune(im._tune),
	_partition(im._partition){
	current=0;
	duration = elapsed = 0;
	//in fact we need to copy samples and attack...
	//will do it later.
}


InstrumentMonophonique::~InstrumentMonophonique(){
	delete current;
	for(uint i=0;i<nb_attack;i++){
		delete _samples[i];
	}
}

string InstrumentMonophonique::getName() const {
	return _name;
}

DynArray<string> InstrumentMonophonique::getTuning() const{
	DynArray<string> d(1,_tune);
	return d;
}

DynArray<string> InstrumentMonophonique::getAttacks() const {
	DynArray<string> ret(nb_attack+1, string());
	for(uint i=0;i<nb_attack;i++){
		ret[i]= attack[i];
	}
	return ret;
}

void InstrumentMonophonique::setName( string Name){
	_name=Name;
}

void InstrumentMonophonique::setTuning( DynArray<string> tune){
	_tune=tune[0];
}

void InstrumentMonophonique::setNote( string name, string file,float speed,short panning,short att,short where=0){// ça devrais plutot prendre un string filename.
	INote in;
	in._note = Note(name,Duration::NOIRE,false);
	in.filename=file;
	in.speed=speed;
	std::cout << "vitesse :" << in.speed << std::endl;
	in._panning=panning;
	in.attack=att;
	in.playing=NULL;
	if(att >= 0 && att < nb_attack && _samples[att]!=0)
		_samples[att]->insert(pair<string, INote>(name, in) );

}

void InstrumentMonophonique::setAttack(string **att){
	int cnt=0;
	while(att[cnt]!=0){
		cnt++;
	}
	attack=DynArray<string>(cnt, string());
	_samples= DynArray<map<string, INote>*>(cnt,NULL);
	for(uint i=0;i<cnt;i++){
		attack[i]= string(*att[i]);
		_samples[i] = new map<string,INote>();
	}
	nb_attack=cnt;
}

void InstrumentMonophonique::setAttack(DynArray<string> att){
	
	attack=att;
	_samples= DynArray<map<string,INote>*>(att.size(),NULL);
	for(uint i=0;i<att.size();i++){
		_samples[i] = new map<string,INote>();
	}
	nb_attack=att.size();	
}


Buffer InstrumentMonophonique::play( uint size){
	Buffer ret = Buffer(size);
	if( elapsed > size){
		if(current!=0)
			naturalEffects(ret,*current,effects);
		//else we return a blank buffer...
		elapsed-=size;
		if(current->isEOF()){
			current=0;
		}
	}else{
		Buffer tret(elapsed);
		if(current!=0)
			naturalEffects(tret,*current, effects);
			//ret.append(current->read(elapsed));
		if(_partition.size()>0){
			INote t = _partition.front();
			_partition.pop();
			std::cout  << t.attack <<endl;
			if(t.attack >= nb_attack) t.attack=0;
			if(t._note.name()=="blank"){
				current=0;
				ret.append(tret);
				for(uint i=duration-elapsed;i<size;i++){
					ret[i]=.0;
				}
			}else if(_samples[t.attack]->find(t._note.name())!=_samples[t.attack]->end()){
				current = SampleFactory::newSample( (*_samples[t.attack])[t._note.name()].filename.c_str());
				ratio=(*_samples[t.attack])[t._note.name()].speed;
				if(ratio!=1.0){
					std::cout << ratio << std::endl;
					PlayingEffect *pitch = new ChangePitch();
					DynArray<double> conf(1,ratio);
					pitch->Tune(conf);
					int psize = t.playing->size()+1;
					effects = new DynArray<PlayingEffect*>(psize , NULL);
					(*effects)[0]=pitch;
					for(uint i=0;i<t.playing->size();i++){
						(*effects)[i+1]=  (*t.playing)[i];
					}
				}else{
					effects=t.playing;
					cout << "Pointers " << effects << " : " << (*_samples[t.attack])[t._note.name()].playing << std::endl;
				}
				Buffer tret2(size - elapsed);
				naturalEffects(tret2,*current, effects);
				//ret << *current;
				ret+=tret+tret2;
				mvolume=t._volume;
				if(current->isEOF())
					current=0;
			}else{
				//no such note...should die ?
			}
			int tmp = size - (duration - elapsed);
			duration = t._note.sampleLength();
			elapsed = duration - tmp;
		}else {
			elapsed=0;
		}
	}
	for(uint j=0;j<size;j++){
		ret[j]*=mvolume;
	}
	return ret;
}
 
Buffer& InstrumentMonophonique::play( Buffer&b){
	uint size = b.capacity();
	b.flush();
	if(elapsed > size){
		if(current!=0)
			naturalEffects(b,*current,effects);
		//else we return a blank buffer...
		elapsed-=size;
	}else{
		Buffer tret(elapsed);
		if(current!=0){
			naturalEffects(tret,*current, effects);
		}
		if(_partition.size()>0){
			INote t = _partition.front();
			_partition.pop();

			if(t._note.name()=="blank"){
				current=0;
				b.append(tret);
				for(uint i=duration-elapsed;i<size;i++){
					b[i]=.0;
				}
			//}else if(_samples[t.attack]->find(t._note.name())!=_samples[t.attack]->end()){
			}else if(_samples[t.attack]->count(t._note.name())!=0){
				ratio=(*_samples[t.attack])[t._note.name()].speed;
				std::cout << "speed " << ratio << std::endl;
				current = SampleFactory::newSample( (*_samples[t.attack])[t._note.name()].filename.c_str());
				mvolume=t._volume;
				if(ratio!=1.0){
					PlayingEffect *pitch = new ChangePitch();
					DynArray<double> conf(1,ratio);
					pitch->Tune(conf);
					int psize = t.playing->size()+1;
					effects = new DynArray<PlayingEffect*>(psize , NULL);
					(*effects)[0]=pitch;
					for(uint i=0;i<t.playing->size();i++){
						(*effects)[i+1]=  (*t.playing)[i];
					}
				}else{
					effects=t.playing;    
				}
				Buffer tret2(size - elapsed);
				naturalEffects(tret2,*current, effects);
				//ret << *current;          
				b+=tret+tret2;              
                                
				//b << *current;            
			}else{                       
				//no such note...should die ?
			}                            
			int tmp = size - (duration - elapsed);
			duration = t._note.sampleLength();
			elapsed = duration - tmp;
		}else{
			elapsed=0;
		}
	}
	for(uint j=0;j<size;j++){
		b[j]*=mvolume;
	}
	return b;
}

void InstrumentMonophonique::addNote(string name, Duration::note_duration_t duration, bool point , uint volume,short att,short where=0,DynArray<PlayingEffect*>* eff=0){
	INote in ;
	in._note = Note(name, duration,point);
	in._volume=pow(10.0, volume/20.0);
	in.attack=att;
	in.playing=eff;
	std::cout << "(add)Effects pointer : " << in.playing << std::endl;
	_partition.push(in);
}

void InstrumentMonophonique::addNote(Note n, uint volume,short att,short where=0,DynArray<PlayingEffect*>* eff=0){
	INote in;
	in._note=n;
	in._volume=pow(10.0,(0.0-volume/100.)/20.0);
	in.attack=att;
	in.playing=eff;
	std::cout << "(add)Effects pointer : " << in.playing << std::endl;
	_partition.push(in);
}


bool InstrumentMonophonique::end() const{
	return elapsed==0 && _partition.size()==0;
}

void InstrumentMonophonique::letRing(bool ring){
//do nothing
}

}

